
The goal of webmorphR is to make the construction of image stimuli more reproducible, with a focus on face stimuli.
This development of this package was funded by ERC grant #647910 (KINSHIP).
The sections below provide brief examples of what webmorphR can be used for. See articles for more detailed instructions on image manipulations, making figures, and making stimuli.
You can install the development version from GitHub with:
# install.packages("remotes")
remotes::install_github("debruine/webmorphR")
Installation can take a few minutes, depending on how many dependency packages you need to install.
library(webmorphR)
#>
#> ************
#> Welcome to webmorphR. For support and examples visit:
#> https://debruine.github.io/webmorphR/
#> ************
wm_opts(plot.maxwidth = 850) # set maximum width for plot output
In this example, we'll load a few faces from the CC-BY licensed Face Research Lab London Set, average them together, and create a figure.
Load 6 faces. If you haven't already downloaded the demo stimulus sets, this code will prompt you to download them. The demo sets are large, so this can take a minute or so.
# remotes::install_github("debruine/stimsets")
face_set <- demo_stim("london", "002|006|007|025|030|066")
plot(face_set, nrow = 1)
These faces already have webmorph templates, so you can make an average. The avg() function sends the images and templates to the server at webmorph.org, which does the processing and sends back the average, so it can take a few seconds. This also means you need an internet connection for this step.
Note: WebMorph was created because of the difficulty of installing desktop PsychoMorph on many computers, which is why this package uses a web-based API for averaging and transforming. You images are deleted from our server immediately after processing.
avg <- avg(face_set)
plot(avg)
Create a figure showing the individual faces and the average with the template superimposed. See plot_stim() for an explanation of the arguments to the plot() function (an alias for plot_stim).
# plot individual faces in a grid the same height as the average face
ind <- plot(face_set,
ncol = 2,
padding = 30,
external_pad = FALSE,
maxwidth = avg$avg$width,
maxheight = avg$avg$height)
# draw template on the face, join with individual grid, and plot
tem <- draw_tem(avg, pt.alpha = 0.5, line.alpha = 0.25)
# combine the ind and tem stimuli and plot
c(ind, tem) %>% plot(nrow = 1)
In this example, we'll transform the individual images, mask and crop them, and put them together in a single compound figure.
First, transform images to make them more average. Transforming manipulates the shape, color, and/or texture of the trans_img by the specified proportion of the different between the from_img and the to_img. In this example, each individual face in face_set is transformed in shape only either by -50% of the difference between that that face an average face, making them more distinctive by exaggerating the non-average features, or by +50%, making them more average.
Set names for the shape, color or texture argument vector to automatically name the output stimuli. The trans() function also sends images to webmorph.org, so can take a minute and requires an internet connection.
dist_avg <- trans(trans_img = face_set,
from_img = face_set,
to_img = avg,
shape = c(distinctive = -0.5, average = 0.5),
color = 0, texture = 0)
plot(dist_avg, nrow = 2)
Next, mask the images with rainbow colours and crop them.
rainbow <- c("#983E82", "#E2A458", "#F5DC70",
"#59935B", "#467AAC", "#61589C")
stimuli <- dist_avg %>%
mask(c("face", "neck", "ears"), fill = rainbow) %>%
crop(0.6, 0.8)
plot(stimuli, nrow = 2)
Save the stimuli into a new directory. This will create a folder in your working directory called “mystimuli” if it doesn't exist.
write_stim(stimuli, dir = "mystimuli")
Easily create figures to illustrate your research. The code below subsets the stimuli to reorder them with average faces first, edits the stimulus names to search and replace a part of the name, adds 120 pixels of black padding to the top of each image, labels them with their name, and plots all images in two rows.
c(subset(stimuli, "average"),
subset(stimuli, "distinctive")) %>%
setnames(pattern = "_03_", replacement = " ") %>%
pad(120, 0, 0, 0, fill = "black") %>%
label(size = 90,
color = rainbow,
gravity = "north",
location = "+0+10") %>%
plot(nrow = 2)
Read in images with webmorph templates, or automatically delineate images with the python module face_recognition or the web-based software Face++. Auto-delineation with Face++ is better, but requires a free API key from Face++. You may be prompted to install a Python module using reticulate::py_install("face_recognition").
Auto-delineation takes a few seconds per face, so you will see a progress bar in the console. You may also see some startup output from reticulate the first time you use this function. For now, only the 7-point auto-delineation is available built in. See the Making Stimuli vignette for instructions on adding the 70-point auto-delineation (it's ~100MB, which is too big to include in an R package).
stimuli <- demo_stim("zoom") %>%
resize(1/2) %>%
auto_delin(replace = TRUE)
draw_tem(stimuli, pt.size = 10) %>% plot()
Alternatively, you can use the Face++ auto-delineator by setting style = "fpp106". This requires you to set up a Face++ account and set some environment variables (see the Making Stimuli vignette). It transfers your images to Face++, so make sure you read their privacy information.
stimuli <- demo_stim("zoom") %>%
resize(1/2) %>%
auto_delin(style = "fpp106", replace = TRUE)
draw_tem(stimuli, pt.size = 8) %>% plot()